package game.leon.seawar.server.handler;

import game.leon.engine.net.EngineConsts;
import game.leon.engine.net.GameSession;
import game.leon.engine.net.GateSession;
import game.leon.engine.net.codec.GameRawMessage;
import game.leon.engine.pattern.Creator;
import game.leon.seawar.server.DelayMessage;
import game.leon.seawar.server.GameMessage;
import game.leon.seawar.server.handler.impl.CreateBattleFun;
import game.leon.seawar.server.handler.impl.LoginFun;
import game.leon.seawar.server.handler.impl.SessonCloseFun;
import game.leon.seawar.vo.*;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;

import static game.leon.seawar.vo.VoCreator.*;

/**
 * User: bianpeng
 * Date: 11-12-29
 */
@Component
public class HandlerService {
    private Logger logger = Logger.getLogger(getClass());
    private static final int STEP = 3;
    // 消息映射, 需要用到两个, 一个是延时消息用的,
    // 因为延时消息不用反序列化
    private Handler<ByteBuffer>[] handlerMap;
    private Handler<BaseVO>[] delayHandlerMap;

    @Autowired
    private SessonCloseFun sessonCloseFun;
    @Autowired
    private LoginFun loginFun;
    @Autowired
    private CreateBattleFun createBattleFun;

    private static int calcMapOffset(int id) {
        return id;
    }

    @SuppressWarnings("unchecked")
    @PostConstruct
    public void init() {
        int n = calcMapOffset(MessageConsts.MAX);
        handlerMap = new Handler[n];
        delayHandlerMap = new Handler[n];

        /// register handlers
        register(EngineConsts.SESSION_CLOSE,
                new FunSuit<Vo.EmptyVO>(sessonCloseFun),
                createEmptyVO);
        register(MessageConsts.LOGIN,
                new FunSuit<Vo.LoginVO>(loginFun),
                createLoginVO);
        register(MessageConsts.BATTLE_CREATE,
                new FunSuit<Vo.CreateBattleParamVO>(createBattleFun),
                createCreateBattleParamVO);
    }
    @SuppressWarnings("unchecked")
    private <T extends BaseVO> void register(
            int message,
            FunSuit<T> funSuit,
            Creator<T> creator) {
        int n = calcMapOffset(message);
        handlerMap[n] = new HandlerSuit<T>(creator, funSuit);
        delayHandlerMap[n] = (Handler<BaseVO>)funSuit;
    }
    //
    // 处理消息, 包括夹带的
    //
    private void execute(GameSession session, int msgId, ByteBuffer buffer) throws IOException {
        int n = calcMapOffset(msgId);
        Handler<ByteBuffer> handler = handlerMap[n];
        if (handler == null) {
            logger.warn(String.format("miss handler %d", msgId));
            return;
        }
        RemoteMessage msg = handler.handle(session, msgId, buffer);
        if (msg != null ) {
            ByteBuffer byteBuffer = new ByteBuffer();
            msg.pack(byteBuffer);
            session.getIoSession().write(new GameRawMessage(msgId, byteBuffer.to_bytes()));
        }
        if (buffer.remain_length() > 0) {
            int attachMsgId = buffer.read_short();
            execute(session, attachMsgId, buffer);
        }
    }
    //
    // 处理外部消息
    //
    public void execute(GameMessage gameMessage) throws IOException {
        int msgId = gameMessage.getRawMessage().getMessage();
        byte[] data = gameMessage.getRawMessage().getData();
        execute(gameMessage.getSession(), msgId,
                new ByteBuffer(data));
    }
    //
    // 延时消息部分逻辑也类似
    //
    public void execute(DelayMessage message) throws IOException {
        int msgId = message.getMessage();
        GameSession session = message.getSession();
        int n = calcMapOffset(msgId);
        Handler<BaseVO> handler = delayHandlerMap[n];
        if (handler != null) {
            RemoteMessage msg = handler.handle(session, msgId, message.getData());
            if (msg != null ) {
                ByteBuffer byteBuffer = new ByteBuffer();
                msg.pack(byteBuffer);
                session.getIoSession().write(new GameRawMessage(msgId, byteBuffer.to_bytes()));
            }
        } else {
            logger.warn(String.format("miss delay handler %d", msgId));
        }
    }
}
